package tech.waterism.service.controller;

import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import tech.waterism.model.SMS3_LAG3_Pipeline;
import tech.waterism.service.cache.ModelTaskCache;
import tech.waterism.service.service.ModelCalculationService;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * SMS3_LAG3 串联模型控制器
 * 
 * <p>提供 SMS_3（产流）→ LAG_3（汇流）串联模型的 REST API 接口</p>
 * 
 * <p><strong>工作流程：</strong></p>
 * <ol>
 *   <li>接收 SMS_3 模型输入数据</li>
 *   <li>运行 SMS_3 产流计算</li>
 *   <li>自动将 SMS_3 的产流输出转换为 LAG_3 的汇流输入</li>
 *   <li>运行 LAG_3 汇流计算</li>
 *   <li>返回最终的流量过程结果</li>
 * </ol>
 * 
 * @author 高宇
 * @since 1.0.0
 */
@Slf4j
@RestController
@RequestMapping("/api/model/sms3-lag3")
@Tag(name = "SMS3_LAG3串联模型", description = "产流+汇流一体化计算 - 新安江产流 → 三水源汇流")
public class SMS3LAG3PipelineController {

    @Autowired
    private ModelCalculationService calculationService;

    @Autowired
    private ModelTaskCache taskCache;

    @PostMapping("/calculate")
    @Operation(
            summary = "SMS3_LAG3串联模型同步计算",
            description = """
                    执行 SMS_3 产流 + LAG_3 汇流串联计算，等待计算完成后返回结果。
                    
                    **适用场景：** 小规模计算（<500时段）、实时性要求高
                    
                    **注意：** 计算期间会阻塞HTTP连接，如计算时间较长建议使用异步接口
                    
                    ## 输入格式（与 SMS_3 完全一致）
                    
                    ```json
                    {
                      "initialState": {
                        "WDP": 25.0,
                        "WUP": 5.0,
                        "WLP": 30.0,
                        "SP": 0.5,
                        "FRP": 0.05
                      },
                      "parameters": {
                        "F": 1313.551,
                        "WM": 131.125,
                        "WUMx": 0.207,
                        "WLMx": 0.745,
                        "B": 0.389,
                        "C": 0.136,
                        "IM": 0.025,
                        "SM": 41.24,
                        "EX": 1.5,
                        "KG": 0.55,
                        "KI": 0.282,
                        "K": 0.737,
                        "monthlyPET": [
                          {"month": 1, "pet": 23.8},
                          ...
                        ]
                      },
                      "rainfallSeries": [
                        {"time": "2025-05-06 08:00:00", "rain": 0.0151},
                        ...
                      ],
                      "clen": 3,
                      "start": "2025-06-05 08:00:00"
                    }
                    ```
                    
                    ### initialState（初始状态对象）
                    - `WDP`: 初始深层土壤含水量 (mm)
                    - `WUP`: 初始上层土壤含水量 (mm)
                    - `WLP`: 初始下层土壤含水量 (mm)
                    - `SP`: 初始自由水蓄量 (mm)
                    - `FRP`: 初始产流率
                    
                    ### parameters（模型参数对象）
                    - `WM`: 流域平均张力水容量 (mm) - 范围: 100-200
                    - `WUMx`: 上层张力水容量比例 - 范围: 0.1-0.3
                    - `WLMx`: 下层张力水容量比例 - 范围: 0.6-0.9
                    - `B`: 蓄水容量曲线指数 - 范围: 0.1-0.4
                    - `C`: 深层蒸散发系数 - 范围: 0.1-0.3
                    - `IM`: 不透水面积占比 - 范围: 0.01-0.05
                    - `SM`: 自由水蓄水库容量 (mm) - 范围: 20-80
                    - `EX`: 自由水蓄水库出流指数 - 范围: 1.0-1.5
                    - `KG`: 地下水出流系数 - 范围: 0.2-0.7
                    - `KI`: 壤中流出流系数 - 范围: 0.2-0.6
                    - `K`: 退水系数 - 范围: 0.3-0.9
                    - `monthlyPET`: 月潜在蒸散发量数组（12个月）
                    
                    ### rainfallSeries（降雨时间序列数组）
                    - 每个元素包含 `time` 和 `rain` 字段
                    
                    ### 根级别参数
                    - `clen`: 时段长度 (小时) - 必需
                    - `start`: 预见期起始时间 - 可选
                    
                    **⚠️ 重要：** `F` (流域面积) 必须包含在 `parameters` 对象中！
                    
                    ## 输出结果（与 LAG_3 输出格式完全一致）
                    - `modelName`: "LAG_3"
                    - `timeSeries`: 时间序列数据（包含 discharge, rain, runoff, sources 等）
                    - `stateTimeSeries`: 状态变量时间序列
                    - `finalState`: 最终状态
                    - `modelParameters`: 模型参数
                    - `metadata`: 元数据
                    
                    ## 算法说明
                    1. **SMS_3 产流计算**：采用新安江三层蒸发模式，计算三水源产流
                    2. **数据转换**：将产流结果自动转换为 LAG_3 的输入格式
                    3. **LAG_3 汇流计算**：采用马斯京根法进行河道演算，输出流量过程
                    """
    )
    public ResponseEntity<?> calculate(@RequestBody Map<String, Object> inputData) {
        try {
            log.info("收到SMS3_LAG3串联模型同步计算请求");
            log.debug("输入参数: {}", JSON.toJSONString(inputData));

            // 执行串联模型计算，返回 LAG_3 模型实例
            tech.waterism.model.LAG_3 lag3Model = SMS3_LAG3_Pipeline.runPipelineWithData(inputData);

            log.info("SMS3_LAG3串联模型计算完成");
            
            // 获取标准化输出对象（与output文件格式一致）
            tech.waterism.model.dto.ModelOutputSimple output = lag3Model.getLastOutput();
            log.debug("计算结果: {}", JSON.toJSONString(output));

            return ResponseEntity.ok(output);

        } catch (IllegalArgumentException e) {
            log.error("SMS3_LAG3串联模型参数错误: {}", e.getMessage());
            return ResponseEntity.badRequest()
                    .body(Map.of(
                            "error", "参数错误",
                            "message", e.getMessage()
                    ));

        } catch (Exception e) {
            log.error("SMS3_LAG3串联模型计算失败", e);
            return ResponseEntity.internalServerError()
                    .body(Map.of(
                            "error", "计算失败",
                            "message", e.getMessage()
                    ));
        }
    }

    @PostMapping("/calculate/async")
    @Operation(
            summary = "SMS3_LAG3串联模型异步计算",
            description = """
                    提交 SMS3_LAG3 串联模型异步计算任务，立即返回任务ID。
                    
                    **适用场景：** 大规模计算（>500时段）、批量计算、对实时性要求不高
                    
                    **工作流程：**
                    1. 提交计算任务，立即返回任务ID
                    2. 使用任务ID轮询查询计算状态和结果
                    3. 计算完成后可获取结果
                    
                    **优势：**
                    - 不阻塞HTTP连接
                    - 支持高并发
                    - 客户端可自由选择查询时机
                    
                    ## 返回结果
                    - `taskId`: 任务ID（用于后续查询）
                    - `status`: 任务状态（SUBMITTED）
                    - `queryUrl`: 查询接口URL
                    """
    )
    public ResponseEntity<?> calculateAsync(@RequestBody Map<String, Object> inputData) {
        try {
            log.info("收到SMS3_LAG3串联模型异步计算请求");
            log.debug("输入参数: {}", JSON.toJSONString(inputData));

            // 生成任务ID
            String taskId = UUID.randomUUID().toString();

            // 提交异步计算任务
            CompletableFuture<tech.waterism.model.dto.ModelOutputSimple> future = 
                calculationService.calculateSMS3LAG3PipelineAsync(inputData);

            // 缓存任务
            taskCache.put(taskId, future, "SMS3_LAG3_Pipeline");

            log.info("SMS3_LAG3串联异步计算任务已提交 - taskId: {}", taskId);

            return ResponseEntity.accepted()
                    .body(Map.of(
                            "taskId", taskId,
                            "status", "SUBMITTED",
                            "message", "串联计算任务已提交，请使用taskId查询结果",
                            "queryUrl", "/api/model/sms3-lag3/task/" + taskId,
                            "modelName", "SMS3_LAG3_Pipeline"
                    ));

        } catch (IllegalArgumentException e) {
            log.error("SMS3_LAG3串联模型参数错误: {}", e.getMessage());
            return ResponseEntity.badRequest()
                    .body(Map.of(
                            "error", "参数错误",
                            "message", e.getMessage()
                    ));

        } catch (Exception e) {
            log.error("提交SMS3_LAG3串联异步任务失败", e);
            return ResponseEntity.internalServerError()
                    .body(Map.of(
                            "error", "提交失败",
                            "message", e.getMessage()
                    ));
        }
    }

    @GetMapping("/task/{taskId}")
    @Operation(
            summary = "查询异步计算任务状态",
            description = """
                    根据任务ID查询 SMS3_LAG3 串联模型异步计算任务的状态和结果。
                    
                    ## 任务状态
                    - `RUNNING`: 计算进行中
                    - `COMPLETED`: 计算完成，返回结果
                    - `FAILED`: 计算失败，返回错误信息
                    - `NOT_FOUND`: 任务不存在或已过期
                    
                    **注意：** 任务结果保留半年，过期后自动清理
                    """
    )
    public ResponseEntity<?> getTaskStatus(@PathVariable String taskId) {
        log.debug("查询任务状态 - taskId: {}", taskId);

        ModelTaskCache.TaskInfo taskInfo = taskCache.getTaskInfo(taskId);

        if (taskInfo == null) {
            log.warn("任务不存在 - taskId: {}", taskId);
            return ResponseEntity.status(404)
                    .body(Map.of(
                            "taskId", taskId,
                            "status", "NOT_FOUND",
                            "message", "任务不存在或已过期"
                    ));
        }

        CompletableFuture<tech.waterism.model.dto.ModelOutputSimple> future = taskInfo.getFuture();

        if (future.isDone()) {
            try {
                // 获取ModelOutputSimple结果
                tech.waterism.model.dto.ModelOutputSimple output = future.get();
                log.info("任务已完成 - taskId: {}", taskId);
                
                // 直接返回ModelOutputSimple对象（与output文件格式一致）
                return ResponseEntity.ok(output);

            } catch (Exception e) {
                log.error("获取任务结果失败 - taskId: {}", taskId, e);
                
                return ResponseEntity.ok(Map.of(
                        "taskId", taskId,
                        "status", "FAILED",
                        "modelName", taskInfo.getModelName(),
                        "error", e.getCause() != null ? e.getCause().getMessage() : e.getMessage()
                ));
            }
        } else {
            log.debug("任务运行中 - taskId: {}", taskId);
            
            return ResponseEntity.ok(Map.of(
                    "taskId", taskId,
                    "status", "RUNNING",
                    "modelName", taskInfo.getModelName(),
                    "createTime", taskInfo.getCreateTime().toString(),
                    "message", "串联计算进行中，请稍后查询"
            ));
        }
    }

    @GetMapping("/info")
    @Operation(
            summary = "获取SMS3_LAG3串联模型信息",
            description = "返回 SMS3_LAG3 串联模型的基本信息、参数说明等"
    )
    public ResponseEntity<?> getModelInfo() {
        // 使用HashMap构建参数Map（因为参数超过10个，不能使用Map.of）
        Map<String, String> parameters = new java.util.HashMap<>();
        parameters.put("F", "流域面积 (km²) - **必需参数**");
        parameters.put("WM", "流域平均张力水容量 (mm) - 范围: 100-200");
        parameters.put("WUMx", "上层张力水容量 (mm) - 范围: 10-40");
        parameters.put("WLMx", "下层张力水容量 (mm) - 范围: 50-120");
        parameters.put("B", "蓄水容量曲线指数 - 范围: 0.1-0.4");
        parameters.put("C", "深层蒸散发系数 - 范围: 0.1-0.3");
        parameters.put("IM", "不透水面积占比 - 范围: 0.01-0.05");
        parameters.put("SM", "自由水蓄水库容量 (mm) - 范围: 20-80");
        parameters.put("EX", "自由水蓄水库出流指数 - 范围: 1.0-1.5");
        parameters.put("KG", "地下水出流系数 - 范围: 0.2-0.5");
        parameters.put("KI", "壤中流出流系数 - 范围: 0.3-0.6");
        parameters.put("K", "地表径流出流系数 - 范围: 0.1-0.9");
        parameters.put("monthlyPET", "月潜在蒸散发量 (mm) - 12个月数据");
        
        return ResponseEntity.ok(Map.of(
                "modelName", "SMS3_LAG3_Pipeline",
                "modelFullName", "SMS_3 + LAG_3 串联模型",
                "description", "新安江产流 + 三水源汇流一体化计算模型",
                "version", "1.0.0",
                "initialState", Map.of(
                        "WDP", "初始深层土壤含水量 (mm)",
                        "WUP", "初始上层土壤含水量 (mm)",
                        "WLP", "初始下层土壤含水量 (mm)",
                        "SP", "初始自由水蓄量 (mm)",
                        "FRP", "初始前期影响雨量 (mm)"
                ),
                "parameters", parameters
        ));
    }

}

